﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Input;
using EpiNEXT.Foundation;
using EpiNEXT.Services;
using EpiNEXT.Services.Collections;
using EpiNEXT.Services.Fields;

namespace EpiNEXT.Applications
{
    public class ProjectViewModel : ObservableObject
    {
        #region Members
        private bool _isShowingPrintPreview = false;
        private bool _isShowingSearch = false;
        private bool _isShowingSave = false;
        private bool _isShowingErrorPanel = false;
        private bool _showTabIndices = false;
        private string _currentStatusMessage = String.Empty;
        private string _currentField = String.Empty;
        private Project _project;
        private bool _isLoadingProject = false;
        public bool _isLoaded = false;
        private static object _recordsLock = new object();
        private static object _formsLock = new object();
        ObservableCollection<FormViewModel> _formCollection = new ObservableCollection<FormViewModel>();
        ObservableCollection<DataGridTableViewModel> _dataGridTableCollection = new ObservableCollection<DataGridTableViewModel>();
        ObservableCollection<CodeListViewModel> _codeListCollection = new ObservableCollection<CodeListViewModel>();
        #endregion // Members

        #region Properties
        //public ICollectionView DataEntryRecordsCollectionView { get; set; }
        public ICollectionView FormsCollectionView { get; set; }
        public ICollectionView DataGridTablesCollectionView { get; set; }
        public ICollectionView CodeListCollectionView { get; set; }

        public bool IsShowingPrintPreview
        {
            get { return this._isShowingPrintPreview; }
            set
            {
                if (IsShowingPrintPreview != value)
                {
                    if (!IsLoaded || IsLoadingProject || !CanExecuteRecordSaveCommands())
                    {
                        this._isShowingPrintPreview = false;
                    }
                    else
                    {
                        this._isShowingPrintPreview = value;
                    }
                    RaisePropertyChanged("IsShowingPrintPreview");
                }
            }
        }

        public bool IsShowingSearch
        {
            get { return this._isShowingSearch; }
            set
            {
                if (IsShowingSearch != value)
                {
                    this._isShowingSearch = value;
                    RaisePropertyChanged("IsShowingSearch");
                }
            }
        }

        public bool IsShowingSave
        {
            get { return this._isShowingSave; }
            set
            {
                if (IsShowingSave != value)
                {
                    this._isShowingSave = value;
                    RaisePropertyChanged("IsShowingSave");
                }
            }
        }

        public bool IsShowingErrorPanel
        {
            get { return this._isShowingErrorPanel; }
            set
            {
                if (IsShowingErrorPanel != value)
                {
                    this._isShowingErrorPanel = value;
                    RaisePropertyChanged("IsShowingErrorPanel");
                }
            }
        }

        public bool IsShowingTabIndices
        {
            get { return this._showTabIndices; }
            set
            {
                this._showTabIndices = value;
                RaisePropertyChanged("IsShowingTabIndices");
            }
        }

        public string CurrentField
        {
            get { return this._currentField; }
            set
            {
                if (this._currentField != value)
                {
                    this._currentField = value;
                    RaisePropertyChanged("CurrentField");

                    if (!String.IsNullOrEmpty(CurrentField))
                    {
                        int bracketIndex = this.CurrentField.IndexOf('[');
                        if (bracketIndex > 0)
                        {
                            Project.CurrentField = this.CurrentField.Substring(0, bracketIndex).Trim();
                        }
                        else
                        {
                            Project.CurrentField = this.CurrentField;
                        }
                    }
                }
            }
        }

        public string CurrentStatusMessage
        {
            get { return _currentStatusMessage; }
            set
            {
                _currentStatusMessage = value;
                RaisePropertyChanged("CurrentStatusMessage");
            }
        }

        public Guid ProjectId
        {
            get { return Project.ProjectId; }
            set
            {
                Project.ProjectId = value;
                RaisePropertyChanged("ProjectId");
            }
        }

        public string Author
        {
            get { return Project.Author; }
            set
            {
                Project.Author = value;
                RaisePropertyChanged("Author");
            }
        }

        public DateTime DateCreated
        {
            get { return Project.DateCreated; }
            set
            {
                Project.DateCreated = value;
                RaisePropertyChanged("DateCreated");
            }
        }

        public DateTime DateLastSaved
        {
            get { return Project.DateLastSaved; }
            set
            {
                Project.DateLastSaved = value;
                RaisePropertyChanged("DateLastSaved");
            }
        }

        public long LastSaved
        {
            get { return Project.LastSaved; }
            set
            {
                Project.LastSaved = value;
                RaisePropertyChanged("LastSaved");
            }
        }

        public long Created
        {
            get { return Project.Created; }
            set
            {
                Project.Created = value;
                RaisePropertyChanged("Created");
            }
        }

        public string Title
        {
            get { return Project.Title; }
            set
            {
                Project.Title = value;
                RaisePropertyChanged("Title");
            }
        }

        public string Summary
        {
            get { return Project.Summary; }
            set
            {
                Project.Summary = value;
                RaisePropertyChanged("Summary");
            }
        }

        public string Description
        {
            get { return Project.Description; }
            set
            {
                Project.Description = value;
                RaisePropertyChanged("Description");
            }
        }

        public FormViewModel SelectedForm
        {
            get
            {
                if (FormsCollectionView == null) return null;
                return FormsCollectionView.CurrentItem as FormViewModel;
            }
        }

        public Guid ParentRecordId { get; private set; }

        public bool IsLoadingProject
        {
            get { return this._isLoadingProject; }
            set
            {
                this._isLoadingProject = value;
                RaisePropertyChanged("IsLoadingProject");
            }
        }

        public bool IsLoaded
        {
            get { return this._isLoaded; }
            set
            {
                if (IsLoaded != value)
                {
                    this._isLoaded = value;
                    RaisePropertyChanged("IsLoaded");
                }
            }
        }

        public bool IsProcessing
        {
            get 
            {
                if (IsLoadingProject)
                {
                    return true;
                }
                else
                {
                    if (Project == null || Project.Database == null)
                    {
                        return false;
                    }
                    else
                    {
                        return Project.Database.IsProcessing;
                    }
                }
            }
        }

        public Project Project
        {
            get { return this._project; }
            private set
            {
                this._project = value;
                RaisePropertyChanged("Project");
            }
        }

        public CodeListViewModel CodeListYesNoViewModel { get; set; }

        public CodeListViewModel CodeListYesNoUnknownViewModel { get; set; }

        public bool HasUnsavedChanges
        {
            get
            {
                // check current item first, this is most efficient
                if (SelectedForm == null) return false;
                if (SelectedForm.RecordsView.CurrentItem != null)
                {
                    if ((SelectedForm.RecordsView.CurrentItem as Record).HasUnsavedChanges == true)
                    {
                        return true;
                    }
                    if ((SelectedForm.RecordsView.CurrentItem as Record).IsInDatabase == false)
                    {
                        return true;
                    }
                }

                foreach (FormViewModel formVM in this.FormsCollectionView)
                {
                    foreach (Record record in formVM.RecordsView)
                    {
                        if (record.HasUnsavedChanges == true || record.IsInDatabase == false)
                        {
                            return true;
                        }
                    }
                }

                foreach (DataGridTableViewModel dataGridTable in this.DataGridTablesCollectionView)
                {
                    foreach (Record record in dataGridTable.RecordsView)
                    {
                        if (record.HasUnsavedChanges == true || record.IsInDatabase == false)
                        {
                            return true;
                        }
                    }
                }

                return false;
            }
        }
        #endregion // Properties

        #region Constructors
        public ProjectViewModel()
        {
            IsLoadingProject = false;
        }
        #endregion // Constructors

        #region Methods
        public void SetSelectedForm(Guid id)
        {
            FormViewModel proposedFormVM = this.GetFormById(id);

            Task.Factory.StartNew(() =>
            {
                // get level of the (soon-to-be) previous form
                int previousLevel = SelectedForm.GetRelationalLevel();
                Guid proposedParentRecordId = new Guid("00000000000000000000000000000000");
                if (SelectedForm.RecordsView != null && SelectedForm.RecordsView.CurrentItem != null)
                {
                    proposedParentRecordId = ((Record)SelectedForm.RecordsView.CurrentItem).Id;
                }
                // change the current form
                this.FormsCollectionView.MoveCurrentTo(proposedFormVM);

                // find out the level of the now-currently-selected form
                int currentLevel = SelectedForm.GetRelationalLevel();

                // if current level > previous level then we navigated to a child form
                if (currentLevel > previousLevel && SelectedForm.ParentFormVM != null && SelectedForm.ParentFormVM.RecordsView != null)
                {
                    ParentRecordId = proposedParentRecordId;
                    string parentRecordIdString = ParentRecordId.ToString();
                    using (SelectedForm.RecordsView.DeferRefresh())
                    {
                        SelectedForm.RecordsView.Filter = obj =>
                        {
                            Record record = obj as Record;
                            if (record.ForeignKeyString.Equals(parentRecordIdString)) return true;
                            else return false;
                        };
                    }
                }
                else if (currentLevel < previousLevel && SelectedForm.ParentFormVM != null && SelectedForm.ParentFormVM.RecordsView != null)
                {
                    // we're navigating back to a parent
                }

                RaisePropertyChanged("SelectedForm");
            }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        }

        private void LoadProject(ProjectInfo projectInfo, FormInfo formInfo = null)
        {
            ProjectFactory factory = new ProjectFactory();
            Project = factory.CreateProject(projectInfo.FilePath);

            _codeListCollection = new ObservableCollection<CodeListViewModel>();
            foreach (CodeList codeList in Project.CodeLists)
            {
                CodeListViewModel codeListVM = new CodeListViewModel(codeList);
                _codeListCollection.Add(codeListVM);
            }
            CodeListCollectionView = new CollectionViewSource { Source = _codeListCollection }.View;
            RaisePropertyChanged("CodeListCollectionView");

            CodeListYesNoViewModel = new CodeListViewModel(Project.CodeListYN);
            CodeListYesNoUnknownViewModel = new CodeListViewModel(Project.CodeListYNU);

            _formCollection = new ObservableCollection<FormViewModel>();
            foreach (Form form in Project.Forms)
            {
                FormViewModel formVM = new FormViewModel(form, this);
                _formCollection.Add(formVM);
            }
            FormsCollectionView = new CollectionViewSource { Source = _formCollection }.View;
            RaisePropertyChanged("FormsCollectionView");

            foreach (FormViewModel formVM in FormsCollectionView)
            {
                formVM.SetParentForm();
            }

            _dataGridTableCollection = new ObservableCollection<DataGridTableViewModel>();
            foreach (DataGridTable dgTable in Project.DataGridTables)
            {
                DataGridTableViewModel dgtVM = new DataGridTableViewModel(dgTable, this);
                _dataGridTableCollection.Add(dgtVM);
            }
            DataGridTablesCollectionView = new CollectionViewSource { Source = _dataGridTableCollection }.View;
            RaisePropertyChanged("DataGridTablesCollectionView");

            foreach (DataGridTableViewModel dgtVM in DataGridTablesCollectionView)
            {
                dgtVM.SetParentForm();
            }

            if (formInfo != null)
            {
                foreach (FormViewModel formVM in this.FormsCollectionView)
                {
                    if (formVM.FormId.Equals(formInfo.Id))
                    {
                        SetSelectedForm(formVM.FormId);
                        break;
                    }
                }
            }
        }

        public virtual void InitalizeCollectionSynchronization()
        {
            System.Windows.Data.BindingOperations.EnableCollectionSynchronization(FormsCollectionView, _formsLock);
        }

        private bool CanExecuteMoveToNextRecordCommand()
        {
            if (SelectedForm == null) return false;
            if (SelectedForm.RecordsView == null) return false;
            if (SelectedForm.RecordsView.CurrentPosition == (SelectedForm.RecordsView.Cast<Record>().Count() - 1)) return false;

            Record currentRecord = SelectedForm.RecordsView.CurrentItem as Record;
            if (currentRecord == null)
            {
                return false;
            }
            else
            {
                return !(currentRecord.HasErrors);
            }
        }

        private bool CanExecuteMoveToPreviousRecordCommand()
        {
            if (SelectedForm == null) return false;
            if (SelectedForm.RecordsView == null) return false;
            if (SelectedForm.RecordsView.CurrentPosition == 0) return false;

            Record currentRecord = SelectedForm.RecordsView.CurrentItem as Record;
            if (currentRecord == null)
            {
                return false;
            }
            else
            {
                return !(currentRecord.HasErrors);
            }
        }

        private bool CanExecuteMoveToFirstRecordCommand()
        {
            return CanExecuteMoveToPreviousRecordCommand();
        }

        private bool CanExecuteMoveToLastRecordCommand()
        {
            return CanExecuteMoveToNextRecordCommand();
        }

        private bool CanExecuteTryUnloadFormCommands()
        {
            if (IsLoadingProject || IsProcessing)
            {
                return false;
            }
            if (SelectedForm == null || SelectedForm.RecordsView == null)
            {
                return false;
            }
            else
            {
                Record currentRecord = SelectedForm.RecordsView.CurrentItem as Record;
                if (currentRecord == null)
                {
                    return true;
                }
                else
                {
                    return !(currentRecord.HasErrors);
                }
            }
        }

        private bool CanExecuteRecordSaveCommands()
        {
            if (IsLoadingProject || IsProcessing)
            {
                return false;
            }
            if (SelectedForm == null || SelectedForm.RecordsView == null)
            {
                return false;
            }
            else
            {
                Record currentRecord = SelectedForm.RecordsView.CurrentItem as Record;
                if (currentRecord == null)
                {
                    return false;
                }
                else
                {
                    return !(currentRecord.HasErrors);
                }
            }
        }

        private bool CanExecuteRecordAddCommands()
        {
            if (IsLoadingProject || IsProcessing)
            {
                return false;
            }
            if (SelectedForm == null || SelectedForm.RecordsView == null)
            {
                return false;
            }
            else
            {
                Record currentRecord = SelectedForm.RecordsView.CurrentItem as Record;
                if (currentRecord == null)
                {
                    return true;
                }
                else
                {
                    return !(currentRecord.HasErrors);
                }
            }
        }

        public FormViewModel GetFormById(Guid id)
        {
            foreach (FormViewModel form in this.FormsCollectionView)
            {
                if (form.FormId.Equals(id))
                {
                    return form;
                }
            }
            throw new InvalidOperationException("Requested form does not exist.");
        }

        public CodeListViewModel GetCodeListById(Guid id)
        {
            foreach (CodeListViewModel codeList in this.CodeListCollectionView)
            {
                if (codeList.Id.Equals(id))
                {
                    return codeList;
                }
            }
            throw new InvalidOperationException("Requested form does not exist.");
        }

        public DataGridTableViewModel GetDataGridTableById(Guid id)
        {
            foreach (DataGridTableViewModel dgTable in this.DataGridTablesCollectionView)
            {
                if (dgTable.FormId.Equals(id))
                {
                    return dgTable;
                }
            }
            throw new InvalidOperationException("Requested data grid table does not exist.");
        }

        public ICommand UpgradeTemplateCommand { get { return new RelayCommand<string>(UpgradeTemplate); } }
        private void UpgradeTemplate(string filePath)
        {
            //EpiNEXT.Core.Legacy.EI7ProjectTemplateConverter converter = new Core.Legacy.EI7ProjectTemplateConverter(filePath);
            //Project newProject = converter.Convert();

            ////string fileName = System.IO.Path.Combine(@"C:\Users\bioha_000\Documents\Visual Studio 2013\Projects\EpiNEXT\EpiNEXT.WPF.View\bin\Debug\Projects", newProject.Title + ".prj");
            ////string fileName = System.IO.Path.Combine(@"C:\Users\knu1\Source\Workspaces\epinext\EpiNEXT\EpiNEXT.WPF.View\bin\Debug\Projects", newProject.Title + ".prj");
            //string fileName = System.IO.Path.Combine(@"C:\Users\EIAdmin\Source\Workspaces\epinext\EpiNEXT\EpiNEXT.WPF.View\bin\Debug\Projects", newProject.Title + ".prj");
            ////newProject.ProjectFileInfo = new System.IO.FileInfo(fileName);
            //newProject.ProjectFilePath = fileName;

            //newProject.Save();
            //newProject.Dispose();
        }

        public ICommand ToggleSearchCommand { get { return new RelayCommand(ToggleSearch, CanExecuteRecordSaveCommands); } }
        private void ToggleSearch()
        {
            IsShowingSearch = !IsShowingSearch;
            SelectedForm.SearchString = String.Empty;
            SelectedForm.SearchRecords.Execute(null);
            if (SelectedForm.RecordsView.CurrentItem == null)
            {
                SelectedForm.RecordsView.MoveCurrentToFirst();
            }
        }

        public ICommand HideSearchCommand { get { return new RelayCommand(HideSearch); } }
        private void HideSearch()
        {
            IsShowingSearch = false;
            SelectedForm.SearchString = String.Empty;
            SelectedForm.SearchRecords.Execute(null);
            if (SelectedForm.RecordsView.CurrentItem == null)
            {
                SelectedForm.RecordsView.MoveCurrentToFirst();
            }
        }

        public ICommand ToggleErrorDisplayCommand { get { return new RelayCommand(ToggleErrorDisplay); } }
        private void ToggleErrorDisplay()
        {
            IsShowingErrorPanel = !IsShowingErrorPanel;
        }

        public ICommand ToggleTabIndicesCommand { get { return new RelayCommand(ToggleTabIndices); } }
        private void ToggleTabIndices()
        {
            IsShowingTabIndices = !IsShowingTabIndices;
        }

        public ICommand TogglePrintPreviewCommand { get { return new RelayCommand(TogglePrintPreview, CanExecuteRecordSaveCommands); } }
        private void TogglePrintPreview()
        {
            IsShowingPrintPreview = !IsShowingPrintPreview;
        }

        public ICommand TryUnloadFormCommand { get { return new RelayCommand(TryUnloadForm, CanExecuteTryUnloadFormCommands); } }
        private void TryUnloadForm()
        {
            if (HasUnsavedChanges)
            {
                IsShowingSave = !IsShowingSave;
            }
            else if(UnloadFormCommand.CanExecute(null))
            {
                UnloadFormCommand.Execute(null);
            }
        }

        public ICommand ExecuteProgramCommand { get { return new RelayCommand<string>(ExecuteProgram); } }
        private void ExecuteProgram(string path)
        {
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = path;
            proc.StartInfo.UseShellExecute = true;
            proc.Start();
        }

        public ICommand GoToFormCommand { get { return new RelayCommand<Guid>(GoToForm); } }
        private void GoToForm(Guid formIdToOpen)
        {
            SetSelectedForm(formIdToOpen);
        }

        public ICommand UpdateComboBoxTargetsCommand { get { return new RelayCommand<ComboBoxField>(UpdateComboBoxTargets); } }
        private void UpdateComboBoxTargets(ComboBoxField comboBoxField)
        {
            UpdateOtherFields();

            // TODO: Can this be moved to the Project class and out of the VM?
            foreach (ListDestinationField destinationField in comboBoxField.ListDestinationFields)
            {
                if (SelectedForm.Fields.Contains(destinationField.Id))
                {
                    IField field = SelectedForm.Fields[destinationField.Id];
                    string columnName = destinationField.TargetName;

                    Record currentRecord = (Record)(SelectedForm.RecordsView.CurrentItem);

                    if (currentRecord != null)
                    {
                        string destinationValue = String.Empty;

                        object rawSourceValue = currentRecord.GetFieldData(comboBoxField);

                        if (rawSourceValue != null)
                        {
                            string sourceValue = rawSourceValue.ToString();

                            foreach (CodeListValue codeListValue in comboBoxField.ListSource.CodeListValues)
                            {
                                if (codeListValue.Store.Equals(sourceValue))
                                {
                                    foreach (CodeListTargetValue targetValue in codeListValue.TargetValues)
                                    {
                                        if (targetValue.Name.Equals(columnName))
                                        {
                                            destinationValue = targetValue.Value;
                                            break;
                                        }
                                    }

                                    break;
                                }
                            }
                        }

                        currentRecord.AddOrUpdateFieldData(field, destinationValue);
                    }
                }
            }
        }

        public ICommand UpdateComboBoxFilterCommand { get { return new RelayCommand<ComboBoxField>(UpdateComboBoxFilter); } }
        private void UpdateComboBoxFilter(ComboBoxField field)
        {
            string currentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture.ToString();

            if (SelectedForm.RecordsView.CurrentItem == null) return;

            UpdateOtherFields();

            foreach (KeyValuePair<ComboBoxField, CodeListViewModel> kvp in SelectedForm.ListFieldLookup)
            {
                ComboBoxField destinationField = kvp.Key;
                CodeListViewModel codeListVM = kvp.Value;

                if (destinationField.ListSourceCascadeSourceFieldId.Equals(field.FieldId))
                {
                    ComboBoxField sourceField = SelectedForm.Fields[destinationField.ListSourceCascadeSourceFieldId] as ComboBoxField;
                    string currentValue = String.Empty;
                    if ((SelectedForm.RecordsView.CurrentItem as Record).GetFieldData(destinationField as IField) != null)
                    {
                        currentValue = (SelectedForm.RecordsView.CurrentItem as Record).GetFieldData(destinationField as IField).ToString();
                    }
                    string sourceValue = String.Empty;
                    if ((SelectedForm.RecordsView.CurrentItem as Record).GetFieldData(sourceField as IField) != null)
                    {
                        sourceValue = (SelectedForm.RecordsView.CurrentItem as Record).GetFieldData(sourceField as IField).ToString();
                    }

                    ICollectionView view = codeListVM.CodeListValuesView;

                    using (view.DeferRefresh())
                    {
                        view.Filter = new Predicate<object>
                            (
                                    listValue =>
                                        (
                                        ((CodeListValue)listValue).Culture == null || 
                                        String.IsNullOrEmpty(((CodeListValue)listValue).Culture) || 
                                        ((CodeListValue)listValue).Culture == currentUICulture
                                        )
                                        &&
                                        ((CodeListValue)listValue).SourceValue == sourceValue
                            );
                    }

                    //CodeListValue selectedListValue = null;
                    foreach (CodeListValue codeListValue in view)
                    {
                        if (codeListValue.Store.Equals(currentValue))
                        {
                            view.MoveCurrentTo(codeListValue);
                        }
                    }
                }
                else if (destinationField.ListSourceCascadeSourceFieldId.Equals(new Guid("00000000-0000-0000-0000-000000000000")))
                {
                    ICollectionView view = codeListVM.CodeListValuesView;
                    if (view.Filter == null)
                    {
                        using (view.DeferRefresh())
                        {
                            view.Filter = new Predicate<object>
                                (
                                        listValue =>
                                            ((CodeListValue)listValue).Culture == null ||
                                            String.IsNullOrEmpty(((CodeListValue)listValue).Culture) || 
                                            ((CodeListValue)listValue).Culture == currentUICulture
                                );
                        }
                    }
                }
            }
        }

        private void UpdateOtherFields()
        {
            if (SelectedForm.RecordsView.CurrentItem == null) return;

            foreach (TextBoxField textField in this.SelectedForm.Fields.TextFields)
            {
                if (textField.IsOtherBox)
                {
                    IField sourceField = SelectedForm.Fields[textField.OtherSourceId];

                    if (sourceField is ComboBoxField)
                    {
                        ComboBoxField comboBoxField = sourceField as ComboBoxField;

                        CodeListViewModel codeListVM = SelectedForm.GetCodeListViewModelForField(comboBoxField);

                        foreach (CodeListValue codeListValue in codeListVM.CodeListValuesView)
                        {
                            if (codeListValue.IsOtherValue)
                            {
                                string listValue = codeListValue.Store;
                                object recordValue = SelectedForm.GetCurrentRecordValue(comboBoxField);

                                if (recordValue != null && listValue.Equals(recordValue.ToString()))
                                {
                                    textField.IsCurrentlyEnabled = true;
                                }
                                else
                                {
                                    textField.IsCurrentlyEnabled = false;
                                    (SelectedForm.RecordsView.CurrentItem as Record).AddOrUpdateFieldData(textField, String.Empty);
                                }
                            }
                        }
                    }
                }
            }
        }

        private void UpdateFilters()
        {
            foreach (DataGridTableViewModel tableVM in this.DataGridTablesCollectionView)
            {
                tableVM.RecordsView.Refresh();
            }

            foreach (IField field in this.SelectedForm.Fields)
            {
                if (field is ComboBoxField)
                {
                    UpdateComboBoxFilter(field as ComboBoxField);
                }
            }

            foreach (TextBoxField textField in this.SelectedForm.Fields.TextFields)
            {
                if (textField.IsOtherBox)
                {
                    IField sourceField = SelectedForm.Fields[textField.OtherSourceId];

                    if (sourceField is ComboBoxField)
                    {
                        ComboBoxField comboBoxField = sourceField as ComboBoxField;

                        CodeListViewModel codeListVM = SelectedForm.GetCodeListViewModelForField(comboBoxField);

                        if (codeListVM.CodeListValuesView.CurrentItem == null)
                        {
                            textField.IsCurrentlyEnabled = false;
                        }
                        else if ((codeListVM.CodeListValuesView.CurrentItem as CodeListValue).IsOtherValue == true)
                        {
                            textField.IsCurrentlyEnabled = true;
                        }
                        else
                        {
                            textField.IsCurrentlyEnabled = false;
                        }
                    }
                }
            }
        }

        private void Reset()
        {
            IsShowingSave = false;
            IsShowingSearch = false;
            IsShowingPrintPreview = false;
            IsShowingErrorPanel = false;
            IsShowingTabIndices = false;
            IsLoaded = false;
        }
        #endregion // Methods

        #region Commands

        public ICommand UnloadFormCommand { get { return new RelayCommand(UnloadFormCommandExecute); } }
        private void UnloadFormCommandExecute()
        {
            IsLoaded = false;
            Project.Dispose();
            Project = null;
            GC.Collect(0, GCCollectionMode.Forced, true);
            Reset();
        }

        public ICommand LoadFormCommand { get { return new RelayCommand<FormInfo>(LoadFormCommandExecute); } }
        private void LoadFormCommandExecute(FormInfo formInfo)
        {
            var context = TaskScheduler.FromCurrentSynchronizationContext();

            IsLoadingProject = true;
            Task.Factory.StartNew(() =>
            {
                LoadProject(formInfo.ProjectInfo, formInfo);
            }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default
            ).ContinueWith(t =>
            {
                InitalizeCollectionSynchronization();

                foreach (FormViewModel formVM in this.FormsCollectionView)
                {
                    formVM.InitalizeCollectionSynchronization();
                }

                foreach (DataGridTableViewModel tableVM in this.DataGridTablesCollectionView)
                {
                    tableVM.InitalizeCollectionSynchronization();
                    tableVM.RecordsView.Filter = obj =>
                    {
                        Record record = obj as Record;

                        if (SelectedForm.RecordsView.CurrentItem == null) return false;

                        if (record.ForeignKey.Equals((SelectedForm.RecordsView.CurrentItem as Record).Id)) return true;
                        else return false;
                    };
                    tableVM.RecordsView.Refresh();
                }

                UpdateFilters();

                IsLoadingProject = false;
                IsLoaded = true;

                SelectedForm.ForceValidationOnCurrentRecord();

            }, context);
        }

        public ICommand MoveToNextRecordCommand { get { return new RelayCommand(MoveToNextRecordExecute, CanExecuteMoveToNextRecordCommand); } }
        private void MoveToNextRecordExecute()
        {
            SelectedForm.RecordsView.MoveCurrentToNext();
            UpdateFilters();
        }

        public ICommand MoveToPreviousRecordCommand { get { return new RelayCommand(MoveToPreviousRecordExecute, CanExecuteMoveToPreviousRecordCommand); } }
        private void MoveToPreviousRecordExecute()
        {
            SelectedForm.RecordsView.MoveCurrentToPrevious();
            UpdateFilters();
        }

        public ICommand MoveToFirstRecordCommand { get { return new RelayCommand(MoveToFirstRecordExecute, CanExecuteMoveToFirstRecordCommand); } }
        private void MoveToFirstRecordExecute()
        {
            SelectedForm.RecordsView.MoveCurrentToFirst();
            UpdateFilters();
        }

        public ICommand MoveToLastRecordCommand { get { return new RelayCommand(MoveToLastRecordExecute, CanExecuteMoveToLastRecordCommand); } }
        private void MoveToLastRecordExecute()
        {
            SelectedForm.RecordsView.MoveCurrentToLast();
            UpdateFilters();
        }

        public ICommand SaveRecordAsyncCommand { get { return new RelayCommand(SaveRecordAsyncExecute, CanExecuteRecordSaveCommands); } }
        private void SaveRecordAsyncExecute()
        {
            CurrentStatusMessage = "Saving...";
            Task<bool> success = Project.Database.SaveRecordAsync(SelectedForm.Form as Form, SelectedForm.RecordsView.CurrentItem as Record);
        }

        public ICommand SaveRecordAndCloseAsyncCommand { get { return new RelayCommand(SaveRecordAndCloseAsyncExecute, CanExecuteRecordSaveCommands); } }
        private void SaveRecordAndCloseAsyncExecute()
        {
            CurrentStatusMessage = "Saving...";

            if (UnloadFormCommand.CanExecute(null))
            {
                try
                {
                    Project.Database.SaveRecord(SelectedForm.Form as Form, SelectedForm.RecordsView.CurrentItem as Record);
                    UnloadFormCommand.Execute(null);
                }
                catch (System.IO.IOException ex)
                {
                    
                }
            }
        }

        public ICommand SaveRecordCommand { get { return new RelayCommand(SaveRecordExecute, CanExecuteRecordSaveCommands); } }
        private void SaveRecordExecute()
        {
            CurrentStatusMessage = "Saving...";
            bool success = Project.Database.SaveRecord(SelectedForm.Form as Form, SelectedForm.RecordsView.CurrentItem as Record);
        }

        public ICommand DeleteRecordCommand { get { return new RelayCommand(DeleteRecordExecute, CanExecuteRecordSaveCommands); } }
        private void DeleteRecordExecute()
        {
            CurrentStatusMessage = "Deleting record...";
            Record currentRecord = SelectedForm.RecordsView.CurrentItem as Record;
            SelectedForm.DeleteRecord(currentRecord);
            UpdateFilters();
        }

        public ICommand AddRecordCommand { get { return new RelayCommand(AddRecordExecute, CanExecuteRecordAddCommands); } }
        private void AddRecordExecute()
        {
            CurrentStatusMessage = "Adding record...";
            Record record = SelectedForm.AddRecord();
            SelectedForm.RecordsView.MoveCurrentTo(record);

            UpdateFilters();
        }

        public ICommand ReturnToParentCommand { get { return new RelayCommand(ReturnToParentExecute, CanExecuteRecordAddCommands); } }
        private void ReturnToParentExecute()
        {
            SetSelectedForm(this.SelectedForm.ParentFormVM.FormId);
        }

        public ICommand ReturnToTopMostParentCommand { get { return new RelayCommand(ReturnToTopMostParentExecute, CanExecuteRecordAddCommands); } }
        private void ReturnToTopMostParentExecute()
        {
            FormViewModel formVM = this.SelectedForm.ParentFormVM;

            bool found = false;
            while (!found)
            {
                if (formVM.ParentFormVM != null)
                {
                    formVM = formVM.ParentFormVM;
                }
                else
                {
                    found = true;
                }
            }

            SetSelectedForm(formVM.FormId);
        }

        #endregion // Commands
    }
}
